package info.pinlab.pinplayer.session;


import info.pinlab.pinplayer.control.AudioController;
import info.pinlab.pinplayer.control.EnrollController;
import info.pinlab.pinplayer.control.SessionControllerWithAudio;
import info.pinlab.pinplayer.control.TaskController;
import info.pinlab.pinplayer.model.response.ResponseContent;
import info.pinlab.pinplayer.model.response.ResponseHeader;
import info.pinlab.pinplayer.model.response.ResponseHeader.ResponseHeaderBuilder;
import info.pinlab.pinplayer.model.task.Task;
import info.pinlab.pinplayer.model.task.TaskInstance;
import info.pinlab.pinplayer.model.task.TaskSet;
import info.pinlab.pinplayer.view.PlayerTopView;
import info.pinlab.pinplayer.view.TaskView;
import info.pinlab.pinsound.PlayerDeviceController;
import info.pinlab.pinsound.RecorderDeviceController;
import info.pinlab.pinsound.app.AudioPlayer;
import info.pinlab.pinsound.app.AudioRecorder;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

public class SessionImpl implements SessionControllerWithAudio{
	public static Logger logger = Logger.getLogger(SessionImpl.class);
	private Configurator conf;
	private PlayerTopView topView = null;
//	private CacheManager cacheManager ;
	
	private TaskSet taskSet;
	private EnrollController enroller = null;
	
	private AudioPlayer audioPlayer = null;
	private AudioRecorder audioRecorder = null;
	private PlayerDeviceController audioPlayerController = null; 
	private RecorderDeviceController audioRecorderController = null;
	
//	private final Map<Class<Task>, Class<TaskView>> taskViewClassMap = new HashMap<Class<Task>, Class<TaskView>>();
//	private final Map<Class<Task>, Class<TaskController>> taskControllerClassMap = new HashMap<Class<Task>, Class<TaskController>>();
	private final Map<Integer, TaskInstance> taskInstances = new HashMap<Integer, TaskInstance>();

	
	//-- caches --//
	private final Map<TaskInstance, TaskView> taskViewCache = new HashMap<TaskInstance, TaskView>();
	private final Map<TaskInstance, TaskController> taskControllerCache = new HashMap<TaskInstance, TaskController>();
	

	
	private int currentTaskIx = 0; //-- always points to the NEXT member! //-- don't use to it!
//	private TaskController lastTaskController = null;
	
	public SessionImpl(Configurator conf){	
		this.conf = conf;
	}

	synchronized public boolean hasNext(){
		if(currentTaskIx >= taskSet.size()){
			return false;
		}
		return true;
	}
	synchronized public boolean hasPrev(){
		if(currentTaskIx <= 1 ){
			return false;
		}
		return true;
	}
	
	private void displayTask(TaskInstance taski){
//		System.out.println("Display " + currentTaskIx + "/" + this.size());
//		System.out.println(taskViewCache.size());
		
		topView.getNaviView().setLabel(currentTaskIx + "/" + this.size());

		TaskView taskView = taskViewCache.get(taski);
		TaskController taskController  = taskControllerCache.get(taski);
		
		if(taskController != null){
			topView.getNaviView().setStepController(taskController);
			if(taskView!=null){
				topView.setTaskView(taskView);
			}else{
				throw new IllegalStateException("TaskView is missing");
			}
			
		}else{
			//-- init view and controller for task 
			String taskClazzName = taski.getTask().getClass().getSimpleName();
			logger.debug("Setting display for '" + taskClazzName +"'");
			String controllClazzName = 
					TaskController.class.getPackage().getName() + "." 
					+ taskClazzName + "Controller";
			logger.debug("Looking for class   '" + controllClazzName+"'");
			
			try{
				Class<?> controllClazz = Class.forName(controllClazzName);
				taskController = (TaskController)controllClazz.newInstance();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (ClassNotFoundException e1) {
				e1.printStackTrace();
			}
			
			//-- set sound if necessary --//
			if(taskController instanceof AudioController){
//				RecorderDeviceController recorderDev = OpenAlRecorder.getInstance();
//				recorderDev.setRecFormat(1, 8000, 16);
				((AudioController)taskController).setAudioRecorder(audioRecorder); 
				((AudioController)taskController).setAudioPlayer(audioPlayer);
			}
			
			taskControllerCache.put(taski, taskController);
			
			taskController.setSessionController(this);
			taskController.setTask(taski);
			topView.getNaviView().setStepController(taskController);
			
			taskView = topView.setTaskView(taski.getTask());
			taskController.setView(taskView);
			taskViewCache.put(taski, taskView);
			taskView.setTaskController(taskController);
		}
	}
	
	public TaskInstance getTaskInstanceByIx(int ix){
		TaskInstance taski = null;
		if(taskInstances.containsKey(ix)){
			taski = taskInstances.get(ix);
		}else{
			final Task task = taskSet.get(currentTaskIx);
			taski = new TaskInstance(task, taskSet.hashCode(), currentTaskIx);
			taskInstances.put(currentTaskIx, taski);
		}
		return taski;
	}
	
	
	
	@Override
	public void setTaskSet(TaskSet tset) {
		taskSet = tset;
	}

	@Override
	public void setEnrollController(EnrollController ec) {
		enroller = ec;
	}

//	@Override
//	public void setCacheManager(CacheManager cm) {
//		cacheManager = cm;
//	}
	

	@Override
	public void startSession(){
		topView.startGui();
		topView.setSessionController(this);
		doNext();
	}
	

	@Override
	public void setTopView(PlayerTopView view) {
		this.topView = view;
	}
	
	@Override
	public void doNext(){
		if(!hasNext()){
			return;
		}
		TaskInstance taski = getTaskInstanceByIx(currentTaskIx);
		currentTaskIx++;
		displayTask(taski);
		
//		if(lastTaskController!=null)
//			lastTaskController.onBeforeNext();
	}
	
	@Override
	public void doPrev() {
		if(!hasPrev()){
			logger.debug("No previous task '" + currentTaskIx);
			return;
		}
		
		TaskInstance taski = getTaskInstanceByIx(currentTaskIx-2);
		currentTaskIx--;
		displayTask(taski);
	}
	
	@Override
	public int size(){
		return taskSet.size();
	}

	
	private ResponseHeader getRepsonseHeader(){
		//TODO: calculate the header!
		return new ResponseHeaderBuilder()
		.build();
	}
	
	
	@Override
	public void enrollResponse(ResponseContent respCont) {
//		ResponseHeader header = getRepsonseHeader();
		if(enroller != null){
			//TODO: implement this!
			enroller.enrollResponse(null);
		}
	}

	
	@Override
	public void reqAudioDevSelector(){
		if(topView!=null){
			List<String> deviceNames = new ArrayList<String>();
			int selectedDevNameIx = topView.showAudioDevSelector(deviceNames);
		}else{
			
		}
	}

	@Override
	public void reqCloseWindow() {
		if(topView!=null){
			boolean confirmed = topView.showCloseConfirmDialog();
			if(confirmed){
				doShutDown();
			}
		}
	}

	
	private void doShutDown(){
		if(audioRecorder!=null){
			audioRecorder.dispose();
		}
//		if(audioRecorderController!= null){
//			audioRecorderController.dispose();
//		}
		if(audioPlayer!=null){
			audioPlayer.dispose();
		}
//		if(audioPlayerController!=null){
//			audioPlayerController.dispose();
//		}
		if(topView!=null){
			topView.dispose();
		}
		//-- do shutdown house keeping if necessary
		System.exit(0);
	}
	
	
	@Override
	public void setAudioPlayerDeviceController(PlayerDeviceController device) {
		audioPlayerController = device;
	}

	@Override
	public void setAudioRecorderDeviceController(RecorderDeviceController device) {
		audioRecorderController = device;
	}

	@Override
	public void setAudioPlayer(AudioPlayer player) {
		audioPlayer = player;
	}

	@Override
	public void setAudioRecorder(AudioRecorder recorder) {
		audioRecorder = recorder;
	}
	
}
